<template>
  <div class="bar">
    <div class="bar-item icon-list">
      <el-tooltip
        class="item"
        effect="dark"
        content="初始化"
        placement="bottom"
      >
        <el-button
          name="init"
          class=""
          size="small"
          icon="el-icon-document-add"
          @click="handleClick"
        >
        </el-button>
      </el-tooltip>
      <el-tooltip
        class="item"
        effect="dark"
        content="撤销 (Cmd + Z)"
        placement="bottom"
      >
        <el-button
          :disabled="!isCanUse.canUndo"
          name="undo"
          class="el-icon-refresh-left"
          size="mini"
          icon="undo"
          @click="handleClick"
        >
        </el-button>
      </el-tooltip>

      <el-tooltip
        class="item"
        effect="dark"
        content="重做 (Cmd + Shift + Z)"
        placement="bottom"
      >
        <el-button
          :disabled="!isCanUse.canRedo"
          name="redo"
          class="el-icon-refresh-right"
          size="mini"
          icon="redo"
          @click="handleClick"
        >
        </el-button>
      </el-tooltip>

      <el-tooltip
        class="item"
        effect="dark"
        content="保存为PNG (Cmd + S)"
        placement="bottom"
      >
        <el-button
          name="savePNG"
          class="el-icon-download"
          size="mini"
          icon="download"
          @click="handleClick"
        >
        </el-button>
      </el-tooltip>

      <el-tooltip
        class="item"
        effect="dark"
        content="保存流程"
        placement="bottom"
      >
        <el-button
          name="save"
          class="el-icon-upload"
          size="mini"
          icon="upload"
          @click="handleSave"
        >
        </el-button>
      </el-tooltip>
      <el-tooltip
        class="item"
        effect="dark"
        content="GPT自动生成"
        placement="bottom"
      >
        <el-button
          name="gpt"
          class="el-icon-search"
          size="mini"
          icon="search"
          @click="handleGPT"
        >
        </el-button>
      </el-tooltip>
    </div>
    <div class="bar-item btn-list">
      <el-button class="btn-save" type="mini" plain @click="handleSubmit"
      >运行
      </el-button>
      <el-button class="btn-cancel" type="mini" plain @click="handleReconnect"
      >重连
      </el-button>
    </div>
    <el-dialog
      title="gpt流程生成辅助"
      :visible.sync="dialogVisible"
      width="30%"
    >
      <div class="container">
        <div class="label-container">
          <span>算法描述</span>
        </div>
        <textarea
          v-model="textInput"
          placeholder="请输入算法描述"
          class="text-area"
        ></textarea>
      </div>
      <!-- 弹窗底部的操作按钮 -->
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="generateGPTResult(textInput)">确 定</el-button>
      </span>
      <div v-if="isLoading" class="loading-overlay">
        <div class="loading-spinner">
          <svg viewBox="0 0 50 50">
            <circle cx="25" cy="25" r="20" fill="none" stroke="#fff" stroke-width="4"
                    :stroke-dasharray="circumference"
                    :stroke-dashoffset="offset"/>
          </svg>
          <p>加载中...</p>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import DagGraph from '../../graph'
import { DataUri } from '@antv/x6'
import { formData } from '../../const/data'
import { offset } from '@antv/x6/es/registry/connection-point/util'
import { cloneDeep } from 'lodash'
import { commonEdge, commonPortsGroups, stencilList, uploadFormData } from '@/views/process/dag/DagEdit/const/config'
import * as api from '@/views/basicoperator/opmanage/api'

let graph = null
export default {
  name: 'ToolBar',
  components: {},
  props: {
    currentSelect: {
      type: String,
      default: 'none'
    }
  },
  data () {
    return {
      isCanUse: {
        canUndo: '',
        canRedo: '',
        canCopy: '',
        canCut: '',
        canPaste: ''
      },
      dialogVisible: false,
      textInput: '',
      isLoading: false,
      circumference: 125.66, // 2 * π * r (r=20)
      offset: 0
    }
  },
  watch: {
    currentSelect (val) {
      const bol = val !== 'none'
      this.isCanUse.canCopy = bol
      this.isCanUse.canCut = bol
      if (!bol) {
        this.isCanUse.canPaste = bol
      }
    }
  },
  mounted () {
    setTimeout(() => {
      graph = DagGraph?.graph
      this.initEvent()
    }, 200)
    // 启动动画
    this.updateLoadingAnimation()
  },
  beforeDestroy () {
    this.isLoading = false // 确保组件销毁时隐藏加载
  },
  methods: {
    // eslint-disable-next-line vue/no-dupe-keys
    offset,
    async generateGPTResult (question) {
      this.isLoading = true // 显示加载提示
      try {
        const res = await api.GetGPTResult({
          question: question
        })
        // const res = {
        //   code: 2000,
        //   msg: 'success',
        //   data: '1. 通道变更  \n2. 裁剪  \n3. 缩放  \n4. 旋转  \n5. 阈值化  \n6. 滤波  \n7. 形态学（边缘检测）  \n8. 特征检测  \n9. 霍夫变换  \n10. 像素统计  \n11. AI算子  \n12. OCR识别'
        // }
        this.isLoading = false // 隐藏加载提示
        this.dialogVisible = false
        if (res.code === 2000) {
          this.$message.success(res.msg)
          this.convertToFlowchart(res.data.result.data)
        } else {
          this.$message.error(res.msg)
        }
      } catch (error) {
        this.isLoading = false
        this.$message.error('请求失败: ' + (error.msg || error.message))
      }
    },
    // 添加动画更新方法
    updateLoadingAnimation () {
      this.offset = (this.offset - 2) % this.circumference
      requestAnimationFrame(this.updateLoadingAnimation)
    },
    // 新增流程图转换方法
    convertToFlowchart(gptResult) {
      graph.clearCells();

      const steps = gptResult
        .split('\n')
        .map(step => step.trim())
        .filter(step => step);

      let yIndex = 50;
      const validNodes = steps.map(text => {
        const foundItem = stencilList.find(item =>
          text.toLowerCase().includes(item.label.toLowerCase())
        );

        if (!foundItem) {
          console.warn(`未找到label为"${text}"的节点`);
          return null; // 返回 null 表示未找到匹配项
        }

        yIndex += 100;
        return graph.createNode({
          x: 100,
          y: yIndex,
          shape: 'pipeline', // 暂时固定为 'pipeline'，可以根据需要调整
          data: cloneDeep(uploadFormData[foundItem.opr]),
          attrs: {
            body: { fillOpacity: '1', strokeOpacity: '1' },
            path: { fill: '#151B21' },
            path2: { fill: '#151B21' },
            label: { text: foundItem.label, fill: '#151B21' },
          },
          ports: commonPortsGroups,
        });
      }).filter(node => node !== null); // 过滤掉 null 节点

      // 创建起始节点
      const start_node_gpt = graph.createNode({
        shape: 'start',
        x: 100,
        y: 50,
        data: formData.start,
        ports: commonPortsGroups,
      });
      validNodes.unshift(start_node_gpt);

      // 添加节点到图中
      graph.addNodes(validNodes);

      // 创建边并添加到图中
      validNodes.forEach((node, index) => {
        if (index < validNodes.length - 1) {
          const edge = graph.createEdge({
            source: { cell: node, port: 'out', anchor: { name: 'bottom' } },
            target: { cell: validNodes[index + 1], port: 'in', anchor: { name: 'top' } },
            ...commonEdge,
          });
          graph.addEdge(edge);
        }
      });

      // 调整图形大小和视图
      graph.resize(800, 600);
      graph.zoomToFit({
        padding: 30,
        maxScale: 1,
        minScale: 0.5,
      });

      graph.centerContent();
      this.$websocket.clearWsData();
    },
    initEvent () {
      const { history } = graph
      history.on('change', () => {
        this.isCanUse.canUndo = history.canUndo()
        this.isCanUse.canRedo = history.canRedo()
      })
      graph.bindKey('ctrl+z', () => {
        if (history.canUndo()) {
          history.undo()
        }
        return false
      })
      graph.bindKey('ctrl+shift+z', () => {
        if (history.canRedo()) {
          history.redo()
        }
        return false
      })
      graph.bindKey('ctrl+d', () => {
        graph.clearCells()
        return false
      })
      graph.bindKey('ctrl+s', () => {
        graph.toPNG((datauri) => {
          DataUri.downloadDataUri(datauri, 'chart.png')
        })
        return false
      })
      graph.bindKey('ctrl+p', () => {
        graph.printPreview()
        return false
      })
      graph.bindKey('ctrl+c', this.copy)
      graph.bindKey('ctrl+v', this.paste)
      graph.bindKey('ctrl+x', this.cut)
    },
    copy () {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.copy(cells)
        this.isCanUse.canPaste = true
      }
      return false
    },
    cut () {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.cut(cells)
        this.isCanUse.canPaste = true
      }
      return false
    },
    paste () {
      if (!graph.isClipboardEmpty()) {
        const cells = graph.paste({ offset: 32 })
        graph.cleanSelection()
        graph.select(cells)
      }
      return false
    },
    handleGPT () {
      this.dialogVisible = true
    },
    handleClick (event) {
      const name = event.currentTarget.name
      switch (name) {
        case 'init':
          this.initGraph()
          this.$websocket.clearWsData()
          break
        case 'undo':
          graph.history.undo()
          break
        case 'redo':
          graph.history.redo()
          break
        case 'delete':
          graph.clearCells()
          break
        case 'savePNG':
          graph.toPNG(
            (dataUri) => {
              // 下载
              DataUri.downloadDataUri(dataUri, 'chartx.png')
            },
            {
              backgroundColor: 'white',
              padding: {
                top: 20,
                right: 30,
                bottom: 40,
                left: 50
              },
              quality: 1
            }
          )
          break
        case 'print':
          graph.printPreview()
          break
        case 'copy':
          this.copy()
          break
        case 'cut':
          this.cut()
          break
        case 'paste':
          this.paste()
          break
        default:
          break
      }
    },
    initGraph () {
      graph.clearCells()
      graph.center() // 内容居中
      graph.zoomTo(1) // 缩放比例
      // eslint-disable-next-line camelcase
      const start_node = graph.createNode({
        shape: 'start',
        x: 100,
        y: 50,
        data: formData.start
      })
      graph.addNode(start_node)
    },
    handleReconnect () {
      this.$websocket.initWebSocket()
    },
    handleSave () {
      this.$emit('saveStrategy')
      console.log(graph.toJSON())
    },
    handleSubmit () {
      this.$websocket.clearWsData()
      console.log('DAG执行测试edges数据', graph.getEdges())
      console.log('DAG数据', graph)
      const formData = new FormData()
      const nodes = graph.getNodes()
      const edges = graph.getEdges()
      const nodesData = []
      const edgesData = []
      nodes.forEach((node) => {
        node.setAttrs({
          body: {
            fill: '#525252',
            stroke: '#2c6fff',
            fillOpacity: '1',
            strokeOpacity: '1'
          },
          label: {
            fill: '#ffffff'
          },
          path: {
            fill: '#ffffff'
          },
          path2: {
            fill: '#ffffff'
          }
        })
        const paramsData = {}
        if (node.data.name?.value == null) {
          console.log('这是自定义算子')
          paramsData.customOp = node.data.id
          paramsData.opName = node.data.name
        }
        const params = node.data.params
        // 将params中每个参数的value取出
        for (const key in params) {
          if (params[key].show === true || key === 'img') {
            paramsData[key] = params[key].value
          }
        }
        const nodeData = {
          id: node.id,
          name: node.data.name?.value == null ? 'customOp' : node.data.name.value,
          params: paramsData
        }
        nodesData.push(nodeData)
      })
      edges.forEach((edge) => {
        const edgeData = {
          id: edge.id,
          labels: edge.labels,
          source: edge.source.cell,
          target: edge.target.cell
        }
        edgesData.push(edgeData)
      })
      // 遍历edges，如果该边的labels为['是']，则将该边的target以及该target的后续node的params中的isTrue置为true，否则置为false
      console.log('node Data测试', nodes)
      edgesData.forEach((edge) => {
        // 如果edge没有labels，则不做处理
        if (edge.labels.length === 0) {
          return
        }
        if (edge.labels[0].attrs.label.text === '是') {
          const targetNode = nodesData.find((node) => node.id === edge.target)
          targetNode.isTrue = 1
          // let targetNodeIndex = nodesData.findIndex((node) => node.id === edge.target);
          const nextNodes = edgesData.filter((edge) => edge.source === edge.target)
          nextNodes.forEach((nextNode) => {
            const nextNodeIndex = nodesData.findIndex((node) => node.id === nextNode.target)
            nodesData[nextNodeIndex].isTrue = 1
          })
        } else {
          const targetNode = nodesData.find((node) => node.id === edge.target)
          targetNode.isTrue = 0
          // let targetNodeIndex = nodesData.findIndex((node) => node.id === edge.target);
          const nextNodes = edgesData.filter((edge) => edge.source === edge.target)
          nextNodes.forEach((nextNode) => {
            const nextNodeIndex = nodesData.findIndex((node) => node.id === nextNode.target)
            nodesData[nextNodeIndex].isTrue = 0
          })
        }
      })
      formData.append('nodes', JSON.stringify(nodesData))
      formData.append('edges', JSON.stringify(edgesData))
      const formDataJson = {}
      for (const key of formData.keys()) {
        formDataJson[key] = formData.get(key)
      }
      console.log('formDataJson', formDataJson)
      this.$websocket.webSocketSend({
        type: 'execute',
        data: formDataJson
      })
    }
  }
}
</script>

<style lang="scss" scoped>
@import "./index.scss";
</style>
